package znet

import (
	"fmt"
	"strconv"
	"zinx/utils"
	"zinx/ziface"
)

type MsgHandle struct {
	//存储不同消息对应的不同处理策略
	Apis map[uint32]ziface.IRouter
	//用于给Worker提供任务的消息队列
	TaskQueue []chan ziface.IRequest
	//WorkerPool中的Worker数量
	WorkerPoolSize uint32
}

func NewMsgHandle() *MsgHandle {
	return &MsgHandle{
		Apis:           make(map[uint32]ziface.IRouter),
		WorkerPoolSize: utils.GlobalObject.WorkerPoolSize,
		TaskQueue:      make([]chan ziface.IRequest, utils.GlobalObject.WorkerPoolSize),
	}
}

func (mh *MsgHandle) DoMsgHandler(request ziface.IRequest) {
	//1.从Request中找到msgId
	handler, ok := mh.Apis[request.GetMsgId()]
	if !ok {
		fmt.Println("api msgId = ", request.GetMsgId(), " is not found!")
		return
	}
	//2.根据msgId调度到对应的router业务
	handler.PreHandle(request)
	handler.Handle(request)
	handler.PostHandle(request)
}

func (mh *MsgHandle) AddRouter(msgId uint32, router ziface.IRouter) {
	//1.判断当前msgId对应的Api是否已经存在
	if _, ok := mh.Apis[msgId]; ok {
		panic("repeat api, msgId = " + strconv.Itoa(int(msgId)))
	}
	//2.添加msgId与Api的绑定关系
	mh.Apis[msgId] = router
	fmt.Println("Add api msgId = ", msgId, "success!")
}

// StartWorkerPool 启动Worker工作池
func (mh *MsgHandle) StartWorkerPool() {
	//根据workPoolSize来决定worker个数，每个worker用一个goroutine承载
	for i := 0; i < int(mh.WorkerPoolSize); i++ {
		//为当前worker对应的消息队列开辟空间
		mh.TaskQueue[i] = make(chan ziface.IRequest, utils.GlobalObject.MaxTaskQueueSize)
		//启动当前的worker，阻塞等待消息队列中的消息
		go mh.StartOneWorker(i)
	}
}

// StartOneWorker 启动Worker工作流程
func (mh *MsgHandle) StartOneWorker(workerId int) {
	fmt.Println("Worker ID = ", workerId, " is started...")
	//阻塞等待
	for {
		select {
		case request := <-mh.TaskQueue[workerId]:
			mh.DoMsgHandler(request)
		}
	}
}

// SendMsgToTaskQueue 将请求交给TaskQueue，由对应的Worker进行处理
func (mh *MsgHandle) SendMsgToTaskQueue(request ziface.IRequest) {
	//轮询分配Worker
	workerId := request.GetConnection().GetConnID() % mh.WorkerPoolSize
	fmt.Println("Add ConnId = ", request.GetConnection().GetConnID(),
		" request MsgId = ", request.GetMsgId(),
		" to WorkerId = ", workerId)
	//将消息发送给Worker的TaskQueue
	mh.TaskQueue[workerId] <- request
}
